﻿using System;

using System.IO;
using Microsoft.WindowsAzure.ServiceRuntime;
using System.Security.AccessControl;
using NougakudoCompanion.Commons;

namespace NougakudoCompanion.Utils
{
    public static class PermissionUtility
    {
        const string NETWORK_SERVICE = "NETWORK SERVICE";
        //const string Network_Service = "NetworkService";
        const string ADMIN = "Administrators";
        const string SYSTEM = "System";

        static public bool Start()
        {

            var windowsId = System.Security.Principal.WindowsIdentity.GetCurrent();
            Logging.Write("Current User ID=" + windowsId.Name);
            var folders = new string[] { RoleEnvironment.GetLocalResource(Constants.RESOURCE_APPLICATION).RootPath, 
                                         RoleEnvironment.GetLocalResource(Constants.RESOURCE_DOWNLOAD).RootPath,
                                         RoleEnvironment.GetLocalResource(Constants.RESOURCE_RUNTIME).RootPath,
                                         RoleEnvironment.GetLocalResource(Constants.RESOURCE_TEMP).RootPath /* Add temp folder */ };
            foreach (var folder in folders)
            {
#if DEBUG
                Logging.Write("Set acl for " + folder);
#endif
                var workFolder = RoleEnvironment.GetConfigurationSettingValue(Constants.AZURE_CONFIG_WORKING_FOLDER);

                var full = Path.Combine(folder, workFolder);
                var ret = SetPermission(full);
                if (!ret)
                {
                    Logging.Write("Set acl failer in SetPermisson.");
                    return false;
                }
            }
            Logging.Write("Set acl complete in SetPermisson.");
            return true;
        }


        static internal bool SetPermission(string folder)
        {
            try
            {
                var ret = CanAddPermission(folder);
#if DEBUG
                Logging.Write("set permission to " + folder);
#endif
                if (!ret)
                {
#if DEBUG
                    Logging.Write("not need acl =" + folder);
#endif
                    return true;
                }
                //var doubleQuate = "\"";

                //var icalcs = new System.Diagnostics.ProcessStartInfo("icacls.exe");
                //icalcs.WorkingDirectory = folder;

                //icalcs.Arguments = doubleQuate + workFolder + doubleQuate +
                //                   " /grant " + Network_Service + ":(OI)(CI)(F)";
                //var proc = System.Diagnostics.Process.Start(icalcs);
                //proc.WaitForExit();
                //Logging.Write("GRANT to NETWORK SERVICE:" + proc.ExitCode.ToString());

                //icalcs.Arguments = doubleQuate + workFolder + doubleQuate +
                //                   " /grant " + ADMIN + ":(OI)(CI)(F)";
                //proc = System.Diagnostics.Process.Start(icalcs);
                //proc.WaitForExit();
                //Logging.Write("GRANT to Administrators:" + proc.ExitCode.ToString());

                //icalcs.Arguments = doubleQuate + workFolder + doubleQuate +
                //                   " /grant " + SYSTEM + ":(OI)(CI)(F)";
                //proc = System.Diagnostics.Process.Start(icalcs);
                //proc.WaitForExit();
                //Logging.Write("GRANT to System:" + proc.ExitCode.ToString());


                DirectoryInfo dirInfo = new DirectoryInfo(folder);
                // Get exists ACL.
                DirectorySecurity dirSec = dirInfo.GetAccessControl();
                // not occur error when set same ACL.
                dirSec.AddAccessRule(
                    new FileSystemAccessRule(NETWORK_SERVICE,
                                             FileSystemRights.FullControl,
                                             InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit,
                                             PropagationFlags.None,
                                             AccessControlType.Allow));
                dirSec.AddAccessRule(
                    new FileSystemAccessRule(ADMIN,
                                             FileSystemRights.FullControl,
                                             InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit,
                                             PropagationFlags.None,
                                             AccessControlType.Allow));
                dirSec.AddAccessRule(
                    new FileSystemAccessRule(SYSTEM,
                                             FileSystemRights.FullControl,
                                             InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit,
                                             PropagationFlags.None,
                                             AccessControlType.Allow));
                dirInfo.SetAccessControl(dirSec);
#if DEBUG
                Logging.Write("Setting acl is sucess.");
#endif
                return true;
            }
            catch (Exception e)
            {
                Logging.Write("Set acl error:" + e.Message);
                return false;
            }
        }

        static bool CanAddPermission(string folder)
        {
            if (Directory.Exists(folder))
            {
#if DEBUG
                Logging.Write("No need to set permission : " + folder);
#endif
                return false;
            }

            try
            {
                Directory.CreateDirectory(folder);

#if DEBUG
                Logging.Write("Created directory. then need network service acl to " + folder);
#endif
                return true;
            }
            catch (Exception e)
            {
                Logging.Write("failed create directory:" + e.Message);
                return false;
            }
        }
    }
}
